#include "Enemy.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
//This code defines a text - based adventure game. The `Game` class constructor initializes the player, game world including rooms, items, and enemies. The `run` method manages the game loop, and other methods handle player actions and check game - over conditions.
// Base enemy class implementation
Enemy::Enemy(const std::string& name, const std::string& desc, 
             unsigned health, unsigned attack, unsigned defense,
             int expReward)
    : Character(name, desc, health, attack, defense), 
      experienceReward(expReward) {
}

int Enemy::getExperienceReward() const {
    return experienceReward;
}

bool Enemy::attack(ICharacter& target) {
    // Basic attack implementation
    bool result = Character::attack(target);
    
    // If attack hits, output attack information
    if (result) {
        std::cout << getName() << " attacked you!" << std::endl;
        if (target.getDefense() > 0) {
            std::cout << "Your defense absorbed some damage!" << std::endl;
        }
        std::cout << "You took " << 
            ((getAttack() > target.getDefense()) ? (getAttack() - target.getDefense()) : 0) << 
            " damage!" << std::endl;
        std::cout << "Your HP: " << target.getHealth() << "/" << target.getMaxHealth() << std::endl;
    }
    
    return result;
}

bool Enemy::operator+(ICharacter& target) {
    // Use + operator to represent attack
    return this->attack(target);
}

// Goblin subclass implementation
Goblin::Goblin(const std::string& name, const std::string& desc, 
               unsigned health, unsigned attack, unsigned defense,
               int expReward, float critChance)
    : Enemy(name, desc, health, attack, defense, expReward),
      criticalChance(critChance) {
}

bool Goblin::attack(ICharacter& target) {
    // Generate a random number to determine if critical hit
    static std::random_device rd;
    static std::mt19937 gen(rd());
    std::uniform_real_distribution<> dis(0.0, 1.0);
    bool isCritical = dis(gen) < criticalChance;
    
    // If critical hit, damage is doubled
    unsigned originalAttack = getAttack();
    if (isCritical) {
        // Use temporary variable to store double attack power instead of directly modifying attackPower
        unsigned tempAttack = originalAttack * 2;
        std::cout << getName() << " launched a critical attack! Double damage!" << std::endl;
        
        // Directly call target.takeDamage instead of modifying attackPower
        bool alive = target.takeDamage(tempAttack);
        
        // Output attack information
        if (target.getDefense() > 0) {
            std::cout << "Target's defense absorbed some damage!" << std::endl;
        }
        unsigned actualDamage = (tempAttack > target.getDefense()) ? (tempAttack - target.getDefense()) : 0;
        std::cout << "Dealt " << actualDamage << " damage!" << std::endl;
        if (alive) {
            std::cout << target.getName() << " HP: " << target.getHealth() << "/" << target.getMaxHealth() << std::endl;
        }
        
        return alive;
    } else {
        // No critical hit, normal attack
        return Enemy::attack(target);
    }
}

// Ghost subclass implementation
Ghost::Ghost(const std::string& name, const std::string& desc, 
             unsigned health, unsigned attack, unsigned defense,
             int expReward, float evadeChance)
    : Enemy(name, desc, health, attack, defense, expReward),
      dodgeChance(evadeChance) {
}

bool Ghost::takeDamage(unsigned damage) {
    // Generate a random number to determine if dodge
    static std::random_device rd;
    static std::mt19937 gen(rd());
    std::uniform_real_distribution<> dis(0.0, 1.0);
    bool isDodged = dis(gen) < dodgeChance;
    
    if (isDodged) {
        std::cout << getName() << " mysteriously dodged the attack!" << std::endl;
        return true; // Dodge successful, still alive
    } else {
        // No dodge, take normal damage
        return Character::takeDamage(damage);
    }
}

// BOSS subclass implementation
Boss::Boss(const std::string& name, const std::string& desc, 
           unsigned health, unsigned attack, unsigned defense,
           int expReward, unsigned heal)
    : Enemy(name, desc, health, attack, defense, expReward),
      enraged(false), healPower(heal) {
}

bool Boss::attack(ICharacter& target) {
    // Check if entering enraged state (health below 30%)
    if (getHealth() < getMaxHealth() * 0.3 && !enraged) {
        enraged = true;
        // Don't directly modify attackPower, add 3 in subsequent calculations
        std::cout << getName() << " entered enraged state! Attack power increased!" << std::endl;
    }
    
    // Get current attack power
    unsigned currentAttack = getAttack();
    if (enraged) {
        currentAttack += 3; // Enraged state adds 3 points of attack power
    }
    
    // Directly call target.takeDamage instead of through Enemy::attack
    bool alive = target.takeDamage(currentAttack);
    
    // Output attack information
    std::cout << getName() << " attacked " << target.getName() << "!" << std::endl;
    if (target.getDefense() > 0) {
        std::cout << "Target's defense absorbed some damage!" << std::endl;
    }
    unsigned actualDamage = (currentAttack > target.getDefense()) ? (currentAttack - target.getDefense()) : 0;
    std::cout << "Dealt " << actualDamage << " damage!" << std::endl;
    if (alive) {
        std::cout << target.getName() << " HP: " << target.getHealth() << "/" << target.getMaxHealth() << std::endl;
    }
    
    // 50% chance for combo attack
    static std::random_device rd;
    static std::mt19937 gen(rd());
    std::uniform_real_distribution<> dis(0.0, 1.0);
    
    if (enraged && dis(gen) < 0.5 && alive) {
        std::cout << getName() << " launched a combo attack!" << std::endl;
        target.takeDamage(currentAttack); // Attack again
    }
    
    return alive;
}

bool Boss::takeDamage(unsigned damage) {
    // First take normal damage
    bool result = Character::takeDamage(damage);
    
    // If health is low but still alive, chance to recover health
    if (result && getHealth() < getMaxHealth() * 0.5) {
        static std::random_device rd;
        static std::mt19937 gen(rd());
        std::uniform_real_distribution<> dis(0.0, 1.0);
        
        if (dis(gen) < 0.3) {  // 30% chance to trigger recovery
            unsigned healAmount = healPower;
            // Create a temporary healing item to restore health
            Item* healEffect = new Item("Self-Healing", "Boss's recovery ability", healAmount, 0, 0);
            addToInventory(healEffect);
            
            std::cout << getName() << " recovered " << healAmount << " health points!" << std::endl;
            std::cout << getName() << " HP: " << getHealth() << "/" << getMaxHealth() << std::endl;
        }
    }
    
    return result;
} 